前兩篇文章介紹如何在Azure SQL Database做自動表格同步,接著使用C#實作讀寫分離程式。
這邊為了簡單示範以 .net core 加上簡易DbConnection SQLHelper舉例,假如有大量建立連線情況,請使用連線池。
【第一步】在 appsettings.json
建立連線字串的資料
{
"DBConnection": {
"MasterConnectionString": "Data Source=Server連接;User ID=帳號;Password=密碼;Initial Catalog=主資料庫;Encrypt=true",
"SlaveConnectionString": [
"Data Source=Server連接;User ID=帳號;Password=密碼;Initial Catalog=附屬資料庫;Encrypt=true;",
"Data Source=Server連接;User ID=帳號;Password=密碼;Initial Catalog=附屬資料庫;Encrypt=true;"
]
}
}
【第二步】建立連線字串的Model類別,注意因為主資料庫只有一個,附屬資料庫可以有多個
所以用List來盛裝,因為有count屬性可以使用,避免後面每次建立連線都運算一次。
public class DBConnection
{
public string MasterConnectionString { get; set; }
public List<string> SlaveConnectionString { get; set; }
}
【第三步】在Startup類別ConfigureServices方法將資料庫物件註冊到SQLHelper
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var dBConnection = Configuration.GetSection("DBConnection");
services.Configure<DBConnection>(dBConnection);
SQLHelper.dBConnection = dBConnection.Get<DBConnection>();
}
}
【第四步】建立抽象類別SQLHelper,為了區分讀寫資料庫的連線建立
,這邊建立兩個方法:
增刪改或者即時性查詢
,使用主服務器的連接字符串。非即時
的查詢像是報表查詢,使用查詢服務器的連接字符串其中為了應付多查詢資料庫分配與效能,我使用時間的Ticks + Mod 附屬資料庫數量
來做平均分配。因為Ticks會隨著時間一點一點遞增,再配合mod得到不超過資料庫數量的特性,取得索引使用非常好用。
public abstract class SQLHelper
{
public static DBConnection dBConnection;/*連線字串註冊在Startup.cs*/
private static readonly System.Data.Common.DbProviderFactory dbProviderFactory = System.Data.SqlClient.SqlClientFactory.Instance;
private static IDbConnection CreateConnectionByConnectionString(string connectionString)
{
var conn = dbProviderFactory.CreateConnection();
conn.ConnectionString = connectionString;
conn.Open();
return conn;
}
public static IDbConnection CreateMasterConnection()
{
return CreateConnectionByConnectionString(dBConnection.MasterConnectionString);
}
public static IDbConnection CreateSlaveConnection()
{
//使用(時間Ticks + mod 附屬資料庫數量) 方式分配 slave
var index = (int)(DateTime.Now.Ticks % (dBConnection.SlaveConnectionString.Count));
var connectionString = dBConnection.SlaveConnectionString[index];
return CreateConnectionByConnectionString(connectionString);
}
}
接著做驗證查詢動作
//模擬兩個時間點的查詢請求,分別使用不同的slave查詢資料庫
var slaveDBCount = SQLHelper.dBConnection.SlaveConnectionString.Count;
using (var conn = SQLHelper.CreateSlaveConnection())
{
var time = DateTime.Parse("2018/11/01 12:00:00.0000000").Ticks;
var isDBAbleStatus = conn.Query<bool>("select top 1 1 ").SingleOrDefault();
Console.WriteLine($"{time} 時間Mod結果為{time%slaveDBCount},使用index為{time%slaveDBCount}的SlaveDB,查詢結果{isDBAbleStatus}");
}
using (var conn = SQLHelper.CreateSlaveConnection())
{
var time = DateTime.Parse("2018/11/01 12:00:00.0000001").Ticks;
var isDBAbleStatus = conn.Query<bool>("select top 1 1 ").SingleOrDefault();
Console.WriteLine($"{time} 時間Mod結果為{time%slaveDBCount},使用index為{time%slaveDBCount}的SlaveDB,查詢結果{isDBAbleStatus}");
}
讀寫分離是專案已經到一定規模,需要將數據從主資料庫同步到其他附屬資料庫,提供非即時
查詢的功能,藉此分散主資料庫負擔
並提高併發量
。當主資料庫在更新資料時,不影響附屬資料庫的查詢,不會發生阻塞lock情況。
其中非即時性
特點很重要,請不要把關鍵業務邏輯
,使用Slave資料庫來完成,所以它不是銀彈,不能應用在所有情況
,個人經驗Slave資料庫常拿來當報表資料庫
使用。